package com.hxc.common.service;

import com.hxc.common.bean.ZdMarkDown;
import com.hxc.common.bean.dataDb.ZdMarkDownDao;
import com.hxc.common.common.GitLabFileData;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.gitlab4j.api.GitLabApi;
import org.gitlab4j.api.RepositoryFileApi;
import org.gitlab4j.api.models.RepositoryFile;
import org.json.JSONArray;
import org.json.JSONObject;
import org.springframework.stereotype.Service;

@Service
public class MarkDownV32Service {

  // gitlab路径
  private static final String GITLAB_URL = "http://10.160.2.29:17004";
  // gitlab v4路径
  private static final String API_URL = "http://10.160.2.29:17004/api/v4";
  // 项目id
  private static final String PROJECT_ID = "103";
  // 分支
  private static final String BRANCH_NAME = "main";
  // 需要获取文档的文件夹
  private static final String PATH = "05.异常SOP";
  // 个人令牌
  private static final String PERSONAL_ACCESS_TOKEN = "gmokyUVHoU3_d9Rwcm4B";
  // 判断图片正则
  private static final String MARKDOWN_IMAGE_PATTERN = "(!\\[[^\\]]*\\])\\(([^\\)]+)\\)";

  public void findMarkdown() throws Exception {
    HttpClient httpClient = HttpClientBuilder.create().build();

    try {
      String apiUrl =
          API_URL + "/projects/" + PROJECT_ID + "/repository/tree?ref=" + BRANCH_NAME + "&path="
              + PATH;
      HttpGet httpGet = new HttpGet(apiUrl);

      httpGet.setHeader("Accept", "application/json");
      httpGet.setHeader("Authorization", "Bearer " + PERSONAL_ACCESS_TOKEN);

      HttpResponse response = httpClient.execute(httpGet);
      String jsonResponse = EntityUtils.toString(response.getEntity());

      System.out.println(jsonResponse);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  //入口
  public List<ZdMarkDown> markdownEnter() throws Exception {
    List<GitLabFileData> gitLabFileData = getGitDataFilePathV2();
    List<ZdMarkDown> zdMarkDownList = findAllMarkdownFiles(gitLabFileData);
    return zdMarkDownList;
  }

  public List<String> getGitDataFilePath() throws Exception {
    HttpClient httpClient = HttpClients.createDefault();
    List<String> filePaths = new ArrayList<>();
    List<GitLabFileData> gitLabFileData = new ArrayList<>();
    // 判断是否读取完毕
    Boolean notNullFlag = true;
    Integer page = 1;

    try {
      while (notNullFlag) {
        String apiUrl =
            API_URL + "/projects/" + PROJECT_ID + "/repository/tree?ref=" + BRANCH_NAME + "&path="
                + PATH + "&per_page=100&page=" + page;

        HttpGet request = new HttpGet(apiUrl);
        request.setHeader("PRIVATE-TOKEN", PERSONAL_ACCESS_TOKEN);
        HttpResponse response = httpClient.execute(request);
        String responseBody = EntityUtils.toString(response.getEntity());
        JSONArray files = new JSONArray(responseBody);
        if (files.length() == 0) {
          notNullFlag = false;
        }
        for (int i = 0; i < files.length(); i++) {
          JSONObject file = files.getJSONObject(i);
          GitLabFileData fileData = new GitLabFileData();
          fileData.setMode(file.getString("mode"));
          fileData.setPath(file.getString("path"));
          fileData.setName(file.getString("name"));
          fileData.setType(file.getString("type"));
          fileData.setId(file.getString("id"));
          gitLabFileData.add(fileData);
          if ("tree".equals(file.getString("type"))) {
            filePaths.add(file.getString("name"));
          }
        }
        page++;
      }
      return filePaths;
    } catch (Exception e) {
      throw new Exception("获取markdown列表失败:" + e.getMessage());
    }
  }


  public List<GitLabFileData> getGitDataFilePathV2() throws Exception {
    HttpClient httpClient = HttpClients.createDefault();
    List<GitLabFileData> gitLabFileData = new ArrayList<>();
    // 判断是否读取完毕
    Boolean notNullFlag = true;
    Integer page = 1;

    try {
      while (notNullFlag) {
        String apiUrl =
            API_URL + "/projects/" + PROJECT_ID + "/repository/tree?ref=" + BRANCH_NAME + "&path="
                + PATH + "&per_page=100&page=" + page;

        HttpGet request = new HttpGet(apiUrl);
        request.setHeader("PRIVATE-TOKEN", PERSONAL_ACCESS_TOKEN);
        HttpResponse response = httpClient.execute(request);
        String responseBody = EntityUtils.toString(response.getEntity());
        JSONArray files = new JSONArray(responseBody);
        if (files.length() == 0) {
          notNullFlag = false;
        }
        for (int i = 0; i < files.length(); i++) {
          JSONObject file = files.getJSONObject(i);
          GitLabFileData fileData = new GitLabFileData();
          fileData.setMode(file.getString("mode"));
          fileData.setPath(file.getString("path"));
          fileData.setName(file.getString("name"));
          fileData.setType(file.getString("type"));
          fileData.setId(file.getString("id"));
          gitLabFileData.add(fileData);

        }
        page++;
      }
      // 将以上第一层路径，递归拿到所有blob文件（非图片）
      List<GitLabFileData> blobGitLabFileDataList = new ArrayList<>();
      for (GitLabFileData fileData : gitLabFileData) {
        // 如果是文件夹（type值为tree），则递归
        if (fileData.getType().equals("tree")) {
          // 递归获取文件
          readFilesRecursively(fileData.getPath(),
              blobGitLabFileDataList);
        } else {
          blobGitLabFileDataList.add(fileData);
        }
      }
      return blobGitLabFileDataList;
    } catch (Exception e) {
      throw new Exception("获取markdown列表失败:" + e.getMessage());
    }
  }

  public String findMarkDownBypathNoWithImage(String path) throws Exception {
    String content = "";
    HttpClient httpClient = HttpClients.createDefault();
    String apiUrl =
        API_URL + "/projects/" + PROJECT_ID + "/repository/tree?ref=" + BRANCH_NAME + "&path="
            + PATH + "/" + URLEncoder
            .encode(path, "UTF-8");
    HttpGet request = new HttpGet(apiUrl);
    request.setHeader("PRIVATE-TOKEN", PERSONAL_ACCESS_TOKEN);
    HttpResponse response = httpClient.execute(request);
    String responseBody = EntityUtils.toString(response.getEntity());
    JSONArray files = new JSONArray(responseBody);
    for (int i = 0; i < files.length(); i++) {
      JSONObject file = files.getJSONObject(i);
      if ("blob".equals(file.getString("type")) && file.getString("name").endsWith(".md")) {
        String filePath = PATH + "/" + path + "/" + file.getString("name");
        String fileContentUrl =
            API_URL + "/projects/" + PROJECT_ID + "/repository/files/" + URLEncoder
                .encode(filePath, "UTF-8") + "/raw?ref=" + BRANCH_NAME;

        HttpGet fileContentRequest = new HttpGet(fileContentUrl);
        fileContentRequest.setHeader("PRIVATE-TOKEN", PERSONAL_ACCESS_TOKEN);

        HttpResponse fileContentResponse = httpClient.execute(fileContentRequest);
        String fileContent = EntityUtils.toString(fileContentResponse.getEntity());

        content = fileContent;
        break;
      }

    }
    return content;
  }

  public void findGitLabBlobsBypathNoWithImage(String path, ZdMarkDown zdMarkDown, String type)
      throws Exception {
    try {
      HttpClient httpClient = HttpClients.createDefault();

      // 对路径中的空格进行替换处理
      String encodedPath = URLEncoder.encode(path, "UTF-8").replace("+", "%D20");

      String fileContentUrl =
          API_URL + "/projects/" + PROJECT_ID + "/repository/files/" + encodedPath + "/raw?ref="
              + BRANCH_NAME;
      HttpGet fileContentRequest = new HttpGet(fileContentUrl);
      fileContentRequest.setHeader("PRIVATE-TOKEN", PERSONAL_ACCESS_TOKEN);

      HttpResponse fileContentResponse = httpClient.execute(fileContentRequest);
      String fileContent = EntityUtils.toString(fileContentResponse.getEntity());
      zdMarkDown.setFilePath(fileContentUrl);
      zdMarkDown.setFileType(type);
      zdMarkDown.setType("异常SOP");
      zdMarkDown.setFileContent(fileContent);
    } catch (Exception e) {
      zdMarkDown.setFileContent("解析文件发生异常:" + e.getMessage() + e);
      e.printStackTrace();
    }
  }

  public String findMarkDownBypathWithImage(String path) throws Exception {
    String markDownNoImageContent = findMarkDownBypathNoWithImage(path);
    Pattern pattern = Pattern.compile(MARKDOWN_IMAGE_PATTERN);
    Matcher matcher = pattern.matcher(markDownNoImageContent);
    StringBuffer sb = new StringBuffer();
    while (matcher.find()) {
      String originalImageTag = matcher.group(0);
      String altText = matcher.group(1);
      String imagePath = matcher.group(2);
      try {
        String base64 = getImageBase64(imagePath, path);
        String transformedImageTag = "![Image](" + base64 + ")";
        matcher.appendReplacement(sb, transformedImageTag);
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
    matcher.appendTail(sb);
    return sb.toString();
  }

  public String getImageBase64(String imagePath, String markDownPath) throws Exception {
    String filePath = markDownPath + "/" + imagePath;
    // 创建 GitLab API 实例
    GitLabApi gitLabApi = new GitLabApi(GITLAB_URL, PERSONAL_ACCESS_TOKEN);
    String base64 = "";
    String fileType = fileType(imagePath);
    // 截取 PATH = "05.异常SOP";后面的字符串
    int index = markDownPath.indexOf(PATH);
    String splitPath = markDownPath;
    if (index != -1) {
      String result = markDownPath.substring(index + PATH.length());
      splitPath = PATH + result + "/" + imagePath;
    }
    // 获取文件内容
    try {
      RepositoryFileApi repositoryFileApi = gitLabApi.getRepositoryFileApi();
      RepositoryFile file = repositoryFileApi.getFile(PROJECT_ID, splitPath, BRANCH_NAME);

      // 将文件内容转换为 Base64
      String base64Content = file.getContent();
      base64 = fileType + base64Content;
      System.out.println(base64Content);
    } catch (Exception e) {
      e.printStackTrace();
    }
    return base64;
  }

  public String fileType(String fileName) throws Exception {
    fileName = fileName.toLowerCase(Locale.ROOT);
    if (fileName.endsWith("png")) {
      return "data:image/png;base64,";
    } else if (fileName.endsWith("jpg") || fileName.endsWith("jpeg")) {
      return "data:image/jpeg;base64,";
    }
    return "";
  }

  // 递归读取所有文件夹和文件
  public static void readFilesRecursively(String path, List<GitLabFileData> gitLabFileDataList)
      throws Exception {
    try {
      String apiUrl =
          API_URL + "/projects/" + PROJECT_ID + "/repository/tree?ref=" + BRANCH_NAME + "&path=";
      String encodedPath = apiUrl + URLEncoder.encode(path, "UTF-8");
      HttpGet request = new HttpGet(encodedPath);
      request.setHeader("PRIVATE-TOKEN", PERSONAL_ACCESS_TOKEN);
      HttpClient httpClient = HttpClients.createDefault();
      HttpResponse response = httpClient.execute(request);
      String responseBody = EntityUtils.toString(response.getEntity());
      JSONArray files = new JSONArray(responseBody);

      for (int i = 0; i < files.length(); i++) {
        JSONObject file = files.getJSONObject(i);
        if ("blob".equals(file.getString("type"))) {
          //判断文件是否为图片是则跳过
          if (file.getString("name").toLowerCase(Locale.ROOT).endsWith(".png") || file
              .getString("name").toLowerCase(Locale.ROOT).endsWith(".jpg")
              || file.getString("name").toLowerCase(Locale.ROOT).endsWith(".jpeg")) {
            continue;
          }
          GitLabFileData gitLabFileData = new GitLabFileData();
          gitLabFileData.setMode(file.getString("mode"));
          gitLabFileData.setPath(file.getString("path"));
          gitLabFileData.setName(file.getString("name"));
          gitLabFileData.setType(file.getString("type"));
          gitLabFileData.setId(file.getString("id"));
          gitLabFileDataList.add(gitLabFileData);
        } else if (file.getString("type").equals("tree")) {
          readFilesRecursively(file.getString("path"), gitLabFileDataList);
        }
      }
    } catch (Exception e) {
      System.out.println("递归读取文件失败:" + e.getMessage());
      e.printStackTrace();
    }
  }


  /**
   * 读取所有markdown文件
   */
  public List<ZdMarkDown> findAllMarkdownFiles(List<GitLabFileData> blobGitLabFileDataList)
      throws Exception {
    try {
      List<ZdMarkDown> zdMarkDownList = new ArrayList<>();
      System.out.println("blobGitLabFileDataList:" + blobGitLabFileDataList.size());
      for (GitLabFileData file : blobGitLabFileDataList) {
        ZdMarkDown zdMarkDown = new ZdMarkDown();
        zdMarkDown.setHandle(UUID.randomUUID().toString());
        if (file.getName().toLowerCase(Locale.ROOT).endsWith(".md")) {
          try {
            zdMarkDown.setFileName(file.getName());
            findGitLabBlobsBypathNoWithImage(file.getPath(), zdMarkDown,
                "md");
            zdMarkDownList.add(zdMarkDown);
          } catch (Exception e) {
            continue;
          }
        } else if (file.getName().toLowerCase(Locale.ROOT).endsWith(".txt")) {
          zdMarkDown.setFileName(file.getName());
          findGitLabBlobsBypathNoWithImage(file.getPath(), zdMarkDown,
              "txt");
          zdMarkDownList.add(zdMarkDown);
          // 获取word文档
        }
      }
      System.out.println("zdMarkDownList:" + zdMarkDownList.size());
      return zdMarkDownList;
    } catch (Exception e) {
      return new ArrayList<>();
    }
  }

  public List<ZdMarkDown> findFileBySearchKey(String searchKey, String searchSetting,
      Connection conn) throws Exception {
    try {
      ZdMarkDownDao zdMarkDownDao = new ZdMarkDownDao(conn);
      List<ZdMarkDown> allMarkDownList = zdMarkDownDao.selectByType("异常SOP");
      // 按照文件名排序
      allMarkDownList.sort(Comparator.comparing(ZdMarkDown::getFileName));
      if (StringUtils.isEmpty(searchKey)) {
        return allMarkDownList;
      }
      List<ZdMarkDown> filteredMarkDownList = new ArrayList<>();
      if (StringUtils.isEmpty(searchSetting) || "keyWord".equals(searchSetting)) {
        filteredMarkDownList = allMarkDownList.stream()
            .filter(o -> StringUtils.isNotEmpty(o.getKeyWord()))
            .filter(o -> o.getKeyWord().contains(searchKey)).collect(Collectors.toList());

//        List<ZdMarkDown> fileNameList = allMarkDownList.stream()
//            .filter(o -> StringUtils.isNotEmpty(o.getFileName()))
//            .filter(o -> o.getFileName().contains(searchKey)).collect(Collectors.toList());
//        filteredMarkDownList.addAll(fileNameList);
        // 未设定关键字,获取keyWord字段为空所有文件
//        List<ZdMarkDown> emptyKeyWordList = allMarkDownList.stream()
//            .filter(o -> StringUtils.isEmpty(o.getKeyWord())).collect(Collectors.toList());
//        filteredMarkDownList.addAll(emptyKeyWordList);
      } else {
        filteredMarkDownList = allMarkDownList.stream()
            .filter(o -> StringUtils.isNotEmpty(o.getFileContent()))
            .filter(o -> o.getFileContent().contains(searchKey)).collect(Collectors.toList());
        //获取文件名有关键字但不在filteredMarkDownList的数据加入进来
        List<ZdMarkDown> fileNameList = allMarkDownList.stream()
            .filter(o -> StringUtils.isNotEmpty(o.getFileName()))
            .filter(o -> o.getFileName().contains(searchKey)).collect(Collectors.toList());
        List<ZdMarkDown> finalFilteredMarkDownList = filteredMarkDownList;
        filteredMarkDownList.addAll(fileNameList.stream()
            .filter(o -> !finalFilteredMarkDownList.contains(o)).collect(Collectors.toList()));
      }
      return filteredMarkDownList;
    } catch (Exception e) {
      throw new Exception("获取文件失败:" + e.getMessage() + e);
    }
  }

  // 查找markdown内容（含图片）
  public String findMarkDownWithImageByData(ZdMarkDown zdMarkDown) throws Exception {
    try {
      String decodedPath = URLDecoder.decode(zdMarkDown.filePath, "UTF-8");

      String fileNamePath = decodedPath.substring(0, decodedPath.lastIndexOf("/"));
      // 获取最后一个斜杠前的字符串
      String filePath = decodedPath.substring(0, fileNamePath.lastIndexOf("/"));
      Pattern pattern = Pattern.compile(MARKDOWN_IMAGE_PATTERN);
      Matcher matcher = pattern.matcher(zdMarkDown.fileContent);

      StringBuffer sb = new StringBuffer();
      while (matcher.find()) {
        String originalImageTag = matcher.group(0);
        String altText = matcher.group(1);
        String imagePath = matcher.group(2);
        try {
          String base64 = getImageBase64(imagePath, filePath);
          String transformedImageTag = "![Image](" + base64 + ")";
          matcher.appendReplacement(sb, transformedImageTag);
        } catch (Exception e) {
          e.printStackTrace();
        }
      }
      matcher.appendTail(sb);
      return sb.toString();
    } catch (Exception e) {
      throw new Exception(e.getMessage());
    }
  }

  public String addKeyWord(ZdMarkDown zdMarkDown, Connection conn) throws Exception {
    try {
      ZdMarkDownDao zdMarkDownDao = new ZdMarkDownDao(conn);
      ZdMarkDown record = zdMarkDownDao.selectByPK(zdMarkDown.getHandle());
      // 获取keyWord,根据,分割转List
      List<String> keyWordList = new ArrayList<>();
      if (StringUtils.isNotEmpty(record.keyWord)) {
        keyWordList = new ArrayList<>(Arrays.asList(record.keyWord.split(",")));
      }
      if (keyWordList.contains(zdMarkDown.keyWord)) {
        throw new Exception("关键字" + zdMarkDown.keyWord + "已存在");
      }
      Integer keyWordLength = 5000;
      if (StringUtils.isNotEmpty(record.keyWord)) {
        if (record.keyWord.length() + zdMarkDown.keyWord.length() + 1 > keyWordLength) {
          throw new Exception("关键字超出维护上限!");
        }
      }
      if (keyWordList.size() > 0) {
        record.keyWord = record.keyWord + "," + zdMarkDown.keyWord;
      } else {
        record.keyWord = zdMarkDown.keyWord;
      }
      return zdMarkDownDao.update(record) > 0 ? "添加关键字成功" : "添加关键字失败";
    } catch (Exception e) {
      throw new Exception("添加关键字失败:" + e.getMessage());
    }
  }

  public String deleteKeyWord(ZdMarkDown zdMarkDown, Connection conn) throws Exception {
    try {
      ZdMarkDownDao zdMarkDownDao = new ZdMarkDownDao(conn);
      ZdMarkDown record = zdMarkDownDao.selectByPK(zdMarkDown.getHandle());
      // 获取keyWord,根据,分割转List
      List<String> keyWordList = new ArrayList<>();
      if (StringUtils.isNotEmpty(record.keyWord)) {
        keyWordList = new ArrayList<>(Arrays.asList(record.keyWord.split(",")));
      }
      if (!keyWordList.contains(zdMarkDown.keyWord)) {
        throw new Exception("关键字" + zdMarkDown.keyWord + "不存在");
      }
      // 将关键字从List移除
      keyWordList.remove(zdMarkDown.keyWord);
      record.keyWord = String.join(",", keyWordList);
      zdMarkDownDao.update(record);
      return zdMarkDownDao.update(record) > 0 ? "删除关键字成功" : "删除关键字失败";
    } catch (Exception e) {
      throw new Exception("删除关键字失败:" + e.getMessage());
    }
  }

  public ZdMarkDown findMarkDownByKey(String handle, Connection conn) throws Exception {
    try {
      ZdMarkDownDao zdMarkDownDao = new ZdMarkDownDao(conn);
      return zdMarkDownDao.selectByPK(handle);
    } catch (Exception e) {
      throw new Exception(e.getMessage());
    }
  }

}
